package com.cooper.mediadb.online;

import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.content.Context;
import android.util.Log;

import com.cooper.android.comm.DataChangedListener;
import com.cooper.android.comm.ReflectionUtils;
import com.cooper.mediadb.Actor;
import com.cooper.mediadb.Media;
import com.cooper.scraper.RunnerSubscribe;
import com.cooper.scraper.show.OnlineFanartResource;

public class OnlineMedia extends Media implements RunnerSubscribe,
		OnlineFanartResource {

	/**
	 * 
	 */
	private static final long serialVersionUID = 870263351485331503L;

	private final static String RESULT_MOVIE_TAG = "movie";
	private final static String DETAILS_PLAY_TAG = "play";
	private final static String DETAILS_PLAY_TITLE_TAG = "title";
	private final static String DETAILS_ACTOR_TAG = "actor";
	private final static String GET_ONLINE_MOVIE_DETAILS_KEY = "GET_ONLINE_MOVIE_DETAILS_";

	public static List<OnlineMedia> onlineMovieFactory(String xml,
			String scraperId, String encodeType, String referer)
			throws XmlPullParserException, IOException {
		List<OnlineMedia> result = new ArrayList<OnlineMedia>();
		XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
		factory.setNamespaceAware(true);
		XmlPullParser xpp = factory.newPullParser();
		
		//Log.d("OnlineMedia","xml:" + xml);
		xpp.setInput(new StringReader(xml));
		

		int eventType = xpp.getEventType();
		OnlineMedia movie = null;
		String currentTag = null;
		String playUrlTitle = "";
		while (eventType != XmlPullParser.END_DOCUMENT) {
			if (eventType == XmlPullParser.START_TAG) {
				currentTag = xpp.getName();
				if (RESULT_MOVIE_TAG.equals(currentTag)) {
					movie = new OnlineMedia(referer, scraperId, encodeType);
				} else if (DETAILS_PLAY_TAG.equals(currentTag)) {
					playUrlTitle = xpp.getAttributeValue(null,
							DETAILS_PLAY_TITLE_TAG);
					if (playUrlTitle == null) {
						playUrlTitle = "";
					}
				}
			} else if (eventType == XmlPullParser.TEXT) {
				if ((movie != null) && (currentTag != null)
						&& !RESULT_MOVIE_TAG.equals(currentTag)
						&& xpp.getText() != null && !"".equals(xpp.getText().trim())) {

					if (DETAILS_PLAY_TAG.equals(currentTag)) {
						movie.getPlayListUrl().put(xpp.getText(), playUrlTitle);
						movie.detailsReady();
					} else if (DETAILS_ACTOR_TAG.equals(currentTag)) {
						
						movie.getActors().add(new Actor(xpp.getText()));
						//Log.d("OnlineMedia","addActor:" + xpp.getText() + "|" + movie.getActors().size());
					} else {

						Object param = xpp.getText();
						try {
							movie.getClass()
									.getMethod(
											ReflectionUtils
													.fieldToJavaSet(currentTag),
											new Class[] { param.getClass() })
									.invoke(movie, new Object[] { param });
						} catch (IllegalArgumentException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (SecurityException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (IllegalAccessException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (InvocationTargetException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (NoSuchMethodException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						}
					}
				}
			} else if (eventType == XmlPullParser.END_TAG) {
				if (RESULT_MOVIE_TAG.equals(xpp.getName())) {
					result.add(movie);
					movie = null;
					currentTag = null;
				}
			}
			eventType = xpp.next();
		}
		Log.d("OnlineMedia","return online media:" + result.size());
		return result;
	}

	protected DataChangedListener detailsReadyListener;

	private String fanartUrl;
	private String posterUrl;
	private String detailsUrl;
	// private String actors;

	private String detailsPageEncodeType;
	private String scraperId;

	private boolean detailsIsReady = false;

	// private List<String> playListUrl = new ArrayList<String>();
	private Map<String, String> playListUrl = new HashMap<String, String>();
	private List<Actor> actors = new ArrayList<Actor>();

	public OnlineMedia() {
		super();
	}

	public OnlineMedia(String referer) {
		super();
		this.referer = referer;
	}

	public OnlineMedia(String referer, String scraperId,
			String detailsPageEncodeType) {
		this(referer);
		this.scraperId = scraperId;
		this.detailsPageEncodeType = detailsPageEncodeType;
	}

	public OnlineMedia(String id, String scraperId, String title, String genre,
			String fanartUrl, String detailsUrl, String detailsPageEncodeType) {
		super();
		this.id = id;
		this.title = title;
		this.genre = genre;
		this.scraperId = scraperId;
		this.fanartUrl = fanartUrl;
		this.detailsUrl = detailsUrl;
		this.detailsPageEncodeType = detailsPageEncodeType;
	}

	public OnlineMedia(String id, String scraperId, String genre, String title,
			String director, String plot, String imdbId, String originaltitle,
			String year, String runtime, String studio, String outline,
			String votes, String tagline, String mpaa, String credits,
			String trailer, String country, String overview, Date joinTime,
			String rating, String fanartUrl, List<Actor> actors,
			Map<String, String> playurls) {
		super(id, genre, title, director, plot, imdbId, originaltitle, year,
				runtime, studio, outline, votes, tagline, mpaa, credits,
				trailer, country, overview, joinTime, rating);
		this.scraperId = scraperId;
		this.actors = actors;
		this.playListUrl = playurls;
		this.fanartUrl = fanartUrl;
		detailsIsReady = true;
	}

	public String getId() {
		return id;
	}

	void detailsReady() {
		detailsIsReady = true;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getFanartUrl() {
		return fanartUrl;
	}

	public void setFanartUrl(String fanartUrl) {
		this.fanartUrl = fanartUrl;
	}

	public String getPosterUrl() {
		return posterUrl;
	}

	public void setPosterUrl(String posterUrl) {
		this.posterUrl = posterUrl;
	}

	public String getDetailsUrl() {
		return detailsUrl;
	}

	public void setDetailsUrl(String detailsUrl) {
		this.detailsUrl = detailsUrl;
	}

	public String getDetailsPageEncodeType() {
		return detailsPageEncodeType;
	}

	public void setDetailsPageEncodeType(String detailsPageEncodeType) {
		this.detailsPageEncodeType = detailsPageEncodeType;
	}

	@Override
	public List<Actor> getActors() {
		return actors;
	}

	public void setActors(List<Actor> actors) {
		this.actors = actors;
	}

	public Map<String, String> getPlayListUrl() {
		return playListUrl;
	}

	public List<MediaSource> getSources(int useType) {
		return MediaSrcMgr.getMediaSources(playListUrl, useType);
	}

	public MediaSource getSourceBySrc(int src) {
		for (MediaSource result : getSources(MediaSrcMgr.GET_SOURCE_ALL)) {
			if (result.getSrc() == src) {
				return result;
			}
		}
		return null;
	}

	public String getScraperId() {
		return scraperId;
	}

	public void setScraperId(String scraperId) {
		this.scraperId = scraperId;
	}

	public void setDetailsReadyListener(DataChangedListener detailsReadyListener) {
		this.detailsReadyListener = detailsReadyListener;
	}

	public boolean detailsIsReady() {
		return detailsIsReady;
	}

	public void prepareDetails(Context context) {
		cancel = false;
		OnlineMediaScrapeRunner.getInstance().subscribe(this);
		OnlineMediaScrapeRunner.getInstance().getResourceDetails(context,
				scraperId, this);
	}

	private boolean cancel = false;

	public void cancelDetails() {
		cancel = true;
		OnlineMediaScrapeRunner.getInstance().cancel(this);
	}

	public void destroy() {
		detailsReadyListener = null;
		OnlineMediaScrapeRunner.getInstance().cancelSubscribe(this);
	}

	private void fillDetails(String xml) throws XmlPullParserException,
			IOException {
		Log.d("OnlineMedia", "fillDetails:" + xml);

		//playListUrl.clear();
		Map<String, String> newPlayListUrl = new HashMap<String, String>();
		List<Actor> newActors = new ArrayList<Actor>();
		//actors.clear();
		XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
		factory.setNamespaceAware(true);
		XmlPullParser xpp = factory.newPullParser();
		xpp.setInput(new StringReader(xml));
		int eventType = xpp.getEventType();
		String currentTag = null;
		String playUrlTitle = "";
		while (eventType != XmlPullParser.END_DOCUMENT) {
			if (eventType == XmlPullParser.START_TAG) {
				currentTag = xpp.getName();
				if (DETAILS_PLAY_TAG.equals(currentTag)) {
					playUrlTitle = xpp.getAttributeValue(null,
							DETAILS_PLAY_TITLE_TAG);
					if (playUrlTitle == null) {
						playUrlTitle = "";
					}
				}
			} else if (eventType == XmlPullParser.TEXT) {
				if ((currentTag != null)
						&& !RESULT_MOVIE_TAG.equals(currentTag)) {
					if (DETAILS_PLAY_TAG.equals(currentTag)) {
						newPlayListUrl.put(xpp.getText(), playUrlTitle);
					} else if (DETAILS_ACTOR_TAG.equals(currentTag)) {
						newActors.add(new Actor(xpp.getText()));
					} else {
						Object param = xpp.getText();
						try {
							getClass().getMethod(
									ReflectionUtils.fieldToJavaSet(currentTag),
									new Class[] { param.getClass() }).invoke(
									this, new Object[] { param });
						} catch (IllegalArgumentException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (SecurityException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (IllegalAccessException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (InvocationTargetException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						} catch (NoSuchMethodException e) {
							Log.e("OnlineMovie", e.getMessage(), e);
						}
					}
				}
			} else if (eventType == XmlPullParser.END_TAG) {
				if (RESULT_MOVIE_TAG.equals(xpp.getName())) {
					currentTag = null;
				} else if (DETAILS_PLAY_TAG.equals(xpp.getName())) {
					playUrlTitle = "";
				}
			}
			eventType = xpp.next();
		}
		
		if (!newActors.isEmpty()){
			actors = newActors; 
		}
		if (!newPlayListUrl.isEmpty()){
			playListUrl = newPlayListUrl;
		}
	}

	@Override
	public void onDownloadComplete(String key, Object data) {
		try {
			fillDetails((String) data);
			detailsIsReady = true;
			if (!cancel && detailsReadyListener != null) {
				detailsReadyListener.onNotifyDataChanged(this, DETAILS_IS_OK,
						null);
			}
		} catch (Exception e) {
			Log.e("OnlineMovie", e.getMessage(), e);
			if (!cancel && detailsReadyListener != null) {
				detailsReadyListener.onNotifyDataChanged(this, DETAILS_IS_FAIL,
						null);
			}
		}
	}

	@Override
	public void onDownloadFail(String key, int errorCode) {
		if (!cancel && detailsReadyListener != null) {
			detailsReadyListener.onNotifyDataChanged(this, DETAILS_IS_FAIL,
					null);
		}
	}

	@Override
	public void onDownloadCancel(String key) {
	}

	@Override
	public boolean subscribed(String key) {
		return key.equals(generateSubscribedKey());
	}

	public String generateSubscribedKey() {
		return GET_ONLINE_MOVIE_DETAILS_KEY + getId();
	}

	private String referer;

	public void setReferer(String referer) {
		this.referer = referer;
	}

	@Override
	public String getReferer() {
		return referer;
	}

}
